home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
macros
/
latex209
/
contrib
/
rail
/
rail.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-11
|
10KB
|
695 lines
/*
* rail.c - railroad diagram utility
*
* 09-Jul-1990 L. Rooijakkers
* 09-Oct-1990 L. Rooijakkers
* 07-Feb-1991 L. Rooijakkers indexing, embedded options
* 08-Feb-1991 L. Rooijakkers small mods for version 1.0 #0
* 12-Feb-1991 L. Rooijakkers minor portability fixes
*
*/
#ifndef lint
static char SccsId[]="@(#)rail 12-Feb-1991";
#endif
#define USAGE "usage: %s [-+acdit] [file]\n"
#include <stdio.h>
#include "patchlevel.h"
#include "rail.h"
#include "gram.h"
extern char *strcat(), *strcpy();
char *myname; /* program name */
char *file; /* input file */
int line; /* input line */
extern FILE *yyin; /* lex input stream */
char *outfile; /* output file */
FILE *outf; /* output stream */
int newline; /* stdout requires a newline */
IDTYPE *idlist; /* identifier list */
IDTYPE *errorid; /* identifier for errors */
/* options */
int altstar; /* alternate star */
int chkgram; /* check grammar */
int treelist; /* list rule trees */
int genindex; /* generate index entry for left hand sides */
#ifdef YYDEBUG
extern int yydebug; /* show yacc debugging */
#endif
int anonymous; /* anonymous rules */
main(argc,argv)
int argc;
char **argv;
{
char *arg, **argp;
unsigned len;
printf("This is Rail, Version %s #%d\n",VERSION,PATCHLEVEL);
newline=0;
myname=argv[0];
for(argp = &argv[1];(arg = *argp)!=NULL;argp++) {
if(*arg!='-' && *arg!='+')
break;
if(setopt(*arg,arg+1)==0)
usage();
}
if(arg!=NULL && *++argp!=NULL)
usage();
if(arg==NULL) {
file="stdin";
outfile="stdout";
yyin=stdin;
outf=stdout;
} else {
len=strlen(arg)+5;
file=mcheck(malloc(len));
outfile=mcheck(malloc(len));
strcat(strcpy(file,arg),".rai");
strcat(strcpy(outfile,arg),".rao");
if((yyin=fopen(file,"r"))==NULL) {
perror(file);
exit(1);
}
if((outf=fopen(outfile,"w"))==NULL) {
perror(outfile);
exit(1);
}
}
printf("(%s",file);
newline=1;
line=1;
fprintf(outf,"%% This file was generated by '%s' from '%s'\n",myname,file);
if(yyparse()!=0)
exit(1);
printf(")\n");
newline=0;
file=NULL;
if(chkgram) {
checkdefs();
if(anonymous)
error("unnamed rules are present",(char *)NULL);
}
exit(0);
/*NOTREACHED*/
}
int setopt(c,s)
char c, *s;
{
int set;
set = c=='-';
while(*s!='\0') {
switch(*s++) {
case 'a':
altstar=set;
break;
case 'c':
chkgram=set;
break;
case 'd':
#ifdef YYDEBUG
yydebug=set;
#endif
break;
case 'i':
genindex=set;
break;
case 't':
treelist=set;
break;
default:
return 0;
}
}
return 1;
}
usage()
{
fprintf(stderr,USAGE,myname);
exit(1);
}
/* error routine for yyparse() */
yyerror(s)
char *s;
{
fatal("%s",s);
}
/* wrap-up routine for yylex() */
yywrap()
{
return(1);
}
/* check for non-NULL pointer */
char *mcheck(s)
char *s;
{
if(s==NULL)
fatal("out of memory",(char *)NULL);
return(s);
}
/* make a new body */
BODYTYPE *newbody(kind,body1,body2)
int kind;
BODYTYPE *body1, *body2;
{
BODYTYPE *body;
body=(BODYTYPE *)mcheck(malloc(sizeof(BODYTYPE)));
body->kind=kind;
body->nlist=0;
body->done=0;
body->id=NULL;
body->text=NULL;
body->annot=NULL;
if(body1!=NULL)
body->list[body->nlist++]=body1;
if(body2!=NULL)
body->list[body->nlist++]=body2;
return(body);
}
/* free a body recursively */
freebody(body)
BODYTYPE *body;
{
int i;
if(body==NULL)
return;
for(i=0;i<body->nlist;i++)
freebody(body->list[i]);
if(body->text!=NULL) {
/* should free text here */
}
free((char *)body);
}
/* test if a body is empty */
int isemptybody(body)
BODYTYPE *body;
{
return(body==NULL || body->kind==EMPTY);
}
/* add to a body list */
static addlist(body1,body2)
BODYTYPE *body1, *body2;
{
if(body1->nlist>=MAXLIST) {
yyerror("list too long");
} else
body1->list[body1->nlist++]=body2;
}
/* add two body lists (for CAT, BAR, PLUS) */
BODYTYPE *addbody(kind,body1,body2)
int kind;
BODYTYPE *body1, *body2;
{
BODYTYPE *body;
int i;
if(body1->kind==kind && !(kind==BAR && body1->done) ) {
body=body1;
} else {
body=newbody(kind,NULLBODY,NULLBODY);
addlist(body,body1);
}
if(body2->kind==kind && !(kind==BAR && body2->done) ) {
for(i=0;i<body2->nlist;i++)
addlist(body,body2->list[i]);
free((char *)body2);
} else {
addlist(body,body2);
}
return(body);
}
/* reverse all concatenations (for PLUS) */
BODYTYPE *revbody(body)
BODYTYPE *body;
{
int i,j;
BODYTYPE *tmp;
if(body->kind==CAT) {
for(i=0,j=body->nlist-1;i<j;i++,j--) {
tmp=body->list[i];
body->list[i]=body->list[j];
body->list[j]=tmp;
}
}
for(i=0;i<body->nlist;i++)
body->list[i]=revbody(body->list[i]);
return(body);
}
/* print a body for debugging */
prtbody(indent,body)
int indent;
BODYTYPE *body;
{
int i;
fprintf(outf,"%% ");
for(i=0;i<indent;i++)
fprintf(outf,". ");
if(body==NULL)
fprintf(outf,"NULL\n");
else {
switch(body->kind) {
case EMPTY:
fprintf(outf,"EMPTY");
break;
case CAT:
fprintf(outf,"CAT");
break;
case BAR:
fprintf(outf,"BAR");
break;
case PLUS:
fprintf(outf,"PLUS");
break;
case ANNOTE:
fprintf(outf,"ANNOTE [%s]",body->text);
break;
case IDENT:
fprintf(outf,"IDENT %s",body->id->name);
break;
case CR:
fprintf(outf,"CR");
break;
case STRNG:
fprintf(outf,"STRNG '%s'",body->text);
break;
default:
fprintf(outf,"UNKNOWN");
break;
}
fprintf(outf," y=%d nexty=%d\n",body->ystart,body->ynext);
for(i=0;i<body->nlist;i++)
prtbody(indent+1,body->list[i]);
}
}
/* output a body */
outbody(id,body)
IDTYPE *id;
BODYTYPE *body;
{
posbody(body,0);
if(treelist)
prtbody(0,body);
fprintf(outf,"\\rail@begin{%d}{",body->ynext);
if(id!=NULL) {
fprintf(outf,"%s",id->name);
}
fprintf(outf,"}\n");
fmtbody(body,"");
fprintf(outf,"\\rail@end\n");
}
/* format a body */
fmtbody(body,cent)
BODYTYPE *body;
char *cent;
{
BODYTYPE *body1;
int i;
char *next;
switch(body->kind) {
case EMPTY:
break;
case CAT:
for(i=0;i<body->nlist;i++)
fmtbody(body->list[i],"");
break;
case BAR:
next="\\rail@bar\n";
for(i=0;i<body->nlist;i++) {
body1=body->list[i];
fprintf(outf,next,body1->ystart);
next="\\rail@nextbar{%d}\n";
fmtbody(body1,"");
}
fprintf(outf,"\\rail@endbar\n");
break;
case PLUS:
fprintf(outf,"\\rail@plus\n");
fmtbody(body->list[0],"");
body1=body->list[1];
fprintf(outf,"\\rail@nextplus{%d}\n",body1->ystart);
fmtbody(body1,"c");
fprintf(outf,"\\rail@endplus\n");
break;
case ANNOTE:
fprintf(outf,"\\rail@annote[%s]\n",body->text);
break;
case IDENT:
if(body->id->kind==TERM)
fprintf(outf,"\\rail@%stoken{%s",cent,body->id->name);
else
fprintf(outf,"\\rail@%snont{%s",cent,body->id->name);
if(body->annot!=NULL)
fprintf(outf,"\\rail@annotebox[%s]",body->annot);
fprintf(outf,"}\n");
break;
case CR:
fprintf(outf,"\\rail@cr{%d}\n",body->ynext-1);
break;
case STRNG:
fprintf(outf,"\\rail@%sterm{%s",cent,body->text);
if(body->annot!=NULL)
fprintf(outf,"\\rail@annotebox[%s]",body->annot);
fprintf(outf,"}\n");
break;
default:
fprintf(outf,"\\rail@unknown\n");
break;
}
}
/* position body (fill in height and ystart) */
posbody(body,ystart)
BODYTYPE *body;
{
BODYTYPE *body1;
int i;
switch(body->kind) {
case CAT:
body->ystart=ystart;
body->ynext=ystart+1;
for(i=0;i<body->nlist;i++) {
body1=body->list[i];
if(body1->kind==CR) {
body1->ystart=ystart;
body1->ynext=body->ynext+2;
ystart=body1->ynext-1;
} else
posbody(body1,ystart);
if(body1->ynext>body->ynext)
body->ynext=body1->ynext;
}
break;
case BAR:
case PLUS:
body->ystart=ystart;
body->ynext=ystart+1;
for(i=0;i<body->nlist;i++) {
body1=body->list[i];
posbody(body1,ystart);
ystart=body1->ynext;
if(body1->ynext>body->ynext)
body->ynext=body1->ynext;
}
break;
case CR:
body->ystart=ystart;
body->ynext=ystart+3;
break;
case EMPTY:
case ANNOTE:
case IDENT:
case STRNG:
default:
body->ystart=ystart;
body->ynext=ystart+1;
break;
}
}
/* output an index entry */
outindex(id)
IDTYPE *id;
{
if(id!=NULL)
fprintf(outf,"\\rail@index{%s}\n",id->name);
}
/* make a new rule list */
RULETYPE *newrule(id,body)
IDTYPE *id;
BODYTYPE *body;
{
RULETYPE *rule;
rule=(RULETYPE *)mcheck(malloc(sizeof(RULETYPE)));
rule->id=id;
rule->body=body;
rule->next=NULL;
return(rule);
}
/* free a rule list */
freerule(rule)
RULETYPE *rule;
{
RULETYPE *rulep;
while(rule!=NULL) {
rulep=rule->next;
freebody(rule->body);
free((char *)rule);
rule=rulep;
}
}
/* add two rule lists */
RULETYPE *addrule(rule1,rule2)
RULETYPE *rule1, *rule2;
{
RULETYPE *rulep;
if(rule1==NULL)
return(rule2);
for(rulep=rule1;rulep->next!=NULL;rulep=rulep->next)
;
rulep->next=rule2;
return(rule1);
}
/* output a rule list */
outrule(rule)
RULETYPE *rule;
{
while(rule!=NULL) {
if(genindex)
outindex(rule->id);
outbody(rule->id,rule->body);
rule=rule->next;
}
}
/* look up an identifier */
IDTYPE *lookup(name)
char *name;
{
IDTYPE *idp, **idq;
for(idq = &idlist;(idp = *idq)!=NULL;idq = &idp->next)
if(strcmp(name,idp->name)==0)
return(idp);
idp=(IDTYPE *)mcheck(malloc(sizeof(IDTYPE)));
idp->name=mcheck(malloc((unsigned)strlen(name)+1));
strcpy(idp->name,name);
idp->next=NULL;
idp->kind=UNKNOWN;
*idq=idp;
return(idp);
}
/* delete an identifier */
delete(id)
IDTYPE *id;
{
IDTYPE *idp, **idq;
for(idq = &idlist;(idp = *idq)!=NULL;idq = &idp->next) {
if(idp==id) {
*idq = idp->next;
free(idp->name);
free((char *)idp);
return;
}
}
}
/* check that there are no undefined identifiers */
checkdefs()
{
IDTYPE *id;
for(id=idlist;id!=NULL;id=id->next)
if(id->kind==TOKEN)
undef(id);
}
/* complain about an undefined identifier */
undef(id)
IDTYPE *id;
{
if(chkgram)
error("undefined identifier '%s'",id->name);
}
/* complain about a redefined identifier */
redef(id)
IDTYPE *id;
{
if(chkgram)
error("redefined identifier '%s'",id->name);
}
/* display an error */
error(f,s)
char *f, *s;
{
if(newline) {
printf("\n");
newline=0;
}
if(file!=NULL)
fprintf(stderr,"%s, line %d: ",file,line);
fprintf(stderr,f,s);
if(errorid!=NULL)
fprintf(stderr," in rule '%s'",errorid->name);
fprintf(stderr,"\n");
}
fatal(f,s)
char *f,*s;
{
error(f,s);
if(outf!=NULL) {
fclose(outf);
unlink(outfile);
}
}